#include "packetcache.h"

guint hash_guid(gconstpointer p) {
	guint hash = *(guint*)p;
	printf("[HASH:%x]\n", hash);
	return hash;
}

gint equal_guid(gconstpointer p1, gconstpointer p2) {
	gint *g1=p1, *g2=p2;
	
	if(*g1==*g2)
		return TRUE;
	else
		return FALSE;
}

void packetcache_add(char guid[NET_DESCRIPTOR_ID_LEN], node *n) {
	n_malloc_zs(p, packet);
	p->n = n;
	g_get_current_time(&p->time);
	guint8 *c_guid = (guint8*)malloc(NET_DESCRIPTOR_ID_LEN);
	memcpy(c_guid, guid, NET_DESCRIPTOR_ID_LEN);
	g_hash_table_insert(packetcache, c_guid, p);
}

void packetcache_free_packet(gpointer data) {
	packet *p = data;
	printf("[packetcache_free_packet]\n");
	free(p);
}

void packetcache_free_guid(gpointer data) {
	guint8 *guid = data;
	int i;
	for(i=0; i<NET_DESCRIPTOR_ID_LEN; i++) {
		free(guid[i]);	
	}
}

node* packetcache_get(guint8 guid[NET_DESCRIPTOR_ID_LEN]) {
	printf("getting GUID:"); printf_guid(guid);printf("\n");
	packet *p = (packet*)g_hash_table_lookup(packetcache, guid);
	node *n;
	
	GTimeVal now;
	g_get_current_time(&now);
	
	if(p==NULL) {
		printf("guid not found.\n");
		printf("HASTABLESIZE:%u\n", g_hash_table_size(packetcache));
		return NULL;
	}
	if((now.tv_sec - p->time.tv_sec) > NET_MAX_PACKET_CACHE_LIFE_SEC) {
		printf("old GUID, deleting\n");
		g_hash_table_remove(packetcache, guid);
		return NULL;
	}
	printf("guid found for node %d\n", n->id);
	printf("HASTABLESIZE:%u\n", g_hash_table_size(packetcache));
	return p->n;
}

gboolean check_packet_age (gpointer key, gpointer value, gpointer user_data) {
	GTimeVal now;
	packet *p = value;
	guint8 *guid = key;
	
	g_get_current_time(&now);
	if((now.tv_sec - p->time.tv_sec) > NET_MAX_PACKET_CACHE_LIFE_SEC) {
		printf("found old GUID\n");
		return TRUE;
	}
	return FALSE;
}

void packetcache_clear() {
	unsigned short removed;
	while(1) {
		sleep(NET_PACKET_CACHE_CLEAR_TIME);
		lock_packetcache();
		removed = g_hash_table_foreach_remove(packetcache,(GHRFunc)check_packet_age,NULL);
		if(removed != 0)
			printf("[packetcache_clear]removed %d entries\n", removed);
		unlock_packetcache();
	}
}

void printf_guint(guint *data, guint *user_data) {
	printf("GUINT: %x\n", *data);
}

void packetcache_printf_keys() {
	GList *keys = g_hash_table_get_keys(packetcache);
	g_list_foreach(keys, (GFunc)printf_guint, NULL);
}

void packetcache_init() {
	pthread_mutex_init(&packetcache_mtx, NULL);
	packetcache = g_hash_table_new_full((GHashFunc)hash_guid,(GCompareFunc)equal_guid, NULL, (GDestroyNotify)packetcache_free_packet);
	pthread_create(&packetcache_handler, NULL, packetcache_clear, NULL);
	pthread_detach(packetcache_handler);
}